﻿package org.papervision3d.core.culling;

import nme.geom.Rectangle;	

import org.papervision3d.core.geom.renderables.Line3D;	
import org.papervision3d.core.culling.ILineCuller;

import org.papervision3d.core.math.util.FastRectangleTools;	


/**
 * @author Seb Lee-Delisle
 */
class RectangleLineCuller implements ILineCuller {

	private var cullingRectangle : Rectangle;
	private var lineBoundsRect : Rectangle;
	
	// temporary rectangle to avoid object creation. 
	private var rectIntersection : Rectangle; 
	
	/**
	 * @Author Seb Lee-Delisle
	 *
	 * RectangleLineCuller
	 * 
	 * This Line Culler culls lines based upon whether they intersect the viewport rectangle.
	 */
	 
	public function new(cullingRectangle:Rectangle = null):Void
	{
		if(cullingRectangle != null){
			this.cullingRectangle = cullingRectangle;	
		}
		lineBoundsRect = new Rectangle(); 
		rectIntersection = new Rectangle(); 		
	}
	
	public function testLine(line : Line3D) : Bool 
	{
		
		// if one or more of the points is behind the camera, then cull. 
		if((!line.v0.vertex3DInstance.visible)||(!line.v1.vertex3DInstance.visible)) return false; 

		var l0x :Float = line.v0.vertex3DInstance.x; 
		var l0y :Float = line.v0.vertex3DInstance.y;
		var l1x :Float = line.v1.vertex3DInstance.x;
		var l1y :Float = line.v1.vertex3DInstance.y;

		// get the line bounds rect 
		lineBoundsRect.width = Math.abs(l1x-l0x);
		lineBoundsRect.height = Math.abs(l1y-l0y);
		
		if(l0x<l1x) lineBoundsRect.x = l0x; 
		else lineBoundsRect.x = l1x; 
		
		if(l0y<l1y) lineBoundsRect.y = l0y; 
		else lineBoundsRect.y = l1y; 
		
		if(cullingRectangle.containsRect(lineBoundsRect)) return true; 
		if(!FastRectangleTools.intersects(lineBoundsRect,cullingRectangle)) return false; 
		
		rectIntersection = FastRectangleTools.intersection(lineBoundsRect, cullingRectangle);
		
		// calculate the equation of the line using the function y = mx + c
		// m is the gradiant
		var m:Float = (l1y-l0y)/(l1x-l0x);
		
		// so if y=mx +c then 
		// l0y = m * l0x +c
		// so... 
		var c:Float = l0y - (m*l0x);
		
		// so now find the point where the line crosses the top of the rectangle
		// y = mx +c; 
		// so also 
		// x = (y - c) / m ; 
		// 
		
		var xcross:Float = (cullingRectangle.top - c)/m;
		
		
		if((xcross>rectIntersection.left) && (xcross<rectIntersection.right)) 
		{
			return true;
		} 
		
		// and the bottom of the rectangle
		xcross = (cullingRectangle.bottom - c)/m;
		if((xcross>rectIntersection.left) && (xcross<rectIntersection.right)) 
		{
			return true; 
		}
		
		// and the left
		var ycross:Float = (m * cullingRectangle.left) +c;
		if((ycross>rectIntersection.top) && (ycross<rectIntersection.bottom)) 
		{
			return true; 
		}
		
		// and the right
		ycross = (m * cullingRectangle.right) +c;
		if((ycross>rectIntersection.top) && (ycross<rectIntersection.bottom)) 
		{
			return true; 
		}
		
	
		//nothing's crossing so no intersection!
		return false; 

	
				
				
				
		
	}
	
	
	
}
